/*================================================================================
// File Name: sha_256_padding.v
// Author: atom
// Created Time: 2023年11月14日 星期二 22时22分30秒
//
//       *         *********       ****            *         *     
//      * *            *          *    *          * *       * *    
//     *   *           *         *      *        *   *     *   *   
//    *******          *         *      *       *     *   *     *  
//   *       *         *          *    *       *       * *       * 
//  *         *        *           ****       *         *         *
================================================================================*/
module sha_256_padding(
    input                   clk,
    input                   rst_n,

    input                   msg_eop,
    input                   msg_vld,
    input           [511:0] msg_dat,
    input           [8:0]   msg_bit_cnt, //0 base
    output                  msg_rdy,

    output  reg             dout_vld,
    output  reg     [511:0] dout
);

wire            padding_tag;
reg     [63:0]  total_bit_cnt_no_eop;
wire    [63:0]  total_bit_cnt;
reg     [63:0]  total_bit_cnt_d

wire    [511:0] padding_data0,padding_data1,padding_data2;
wire    [511:0] padding_data;

wire            extra_padding_c,extra_padding_c1;
reg             extra_padding_d,extra_padding_d1;

wire    [511:0] extra_padding_data1,extra_padding_data2;
wire    [511:0] extra_padding_data;


//only check if need padding when padding_tag set
assign padding_tag = msg_eop & msg_vld;

//happen extra cycle padding
assign extra_padding_c = (padding_tag & msg_bit_cnt[8:0]>9'd486);
assign extra_padding_c1= (padding_tag & msg_bit_cnt[8:0]==9'd511);  //512 bits

assign msg_rdy = ~extra_padding_d;

//totally bit cnt
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        total_bit_cnt_no_eop[63:0] <= 64'b0;
    else if(padding_tag)
        total_bit_cnt_no_eop[63:0] <= 64'b0;
    else if(msg_vld)
        total_bit_cnt_no_eop[63:0] <= total_bit_cnt_no_eop[63:0] + msg_bit_cnt[8:0];
end

//eop real bit cnt
assign total_bit_cnt[63:0] = total_bit_cnt_no_eop[63:0] + msg_bit_cnt[8:0];

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        total_bit_cnt_d[63:0] <= 64'b0;
    else
        total_bit_cnt_d[63:0] <= total_bit_cnt[63:0];
end


always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        extra_padding_d <= 1'b0;
        extra_padding_d1<= 1'b0;
    end
    else begin
        extra_padding_d <= extra_padding_c;
        extra_padding_d1<= extra_padding_c1;
    end
end 

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        dout_vld <= 1'b0;
    else
        dout_vld <= msg_vld | extra_padding_d;
end

//eop bit cnt < 488 padding
assign msg_mask[511:0] = {512{1'b1}} << (512-msg_bit_cnt[8:0]);
assign msg_assert[511:0] = { {511{1'b0}},1'b1} << (511-msg_bit_cnt[8:0]);


assign padding_data_tmp[511:0] = msg_dat[511:0] & msg_mask[511:0] | msg_assert[511:0];
assign padding_data0[511:0] = {padding_data_tmp[511:64],total_bit_cnt[63:0]};

/*=====================================================
eop bit 488 < cnt < 512 padding, it will increase 1cycle
'1' still in current cycle, but length remain in next cycle
=====================================================*/
assign padding_data1[511:0] = padding_data_tmp[511:0];
assign extra_padding_data1[511:0] = {488'b0,total_bit_cnt_d[63:0]};
/*=====================================================
eop bit cnt = 512 padding, it will increase 1cycle
'1' and length both remain in next cycle
=====================================================*/
assign padding_data2[511:0] = msg_dat[511:0];
assign extra_padding_data2[511:0] = {1'b1,487'b0,total_bit_cnt_d[63:0]};

assign padding_data[511:0] = extra_padding_c1 ? padding_data2[511:0] :
                             extra_padding_c  ? padding_data1[511:0] : padding_data0[511:0];

assign extra_padding_data[511:0] = extra_padding_d1 ? extra_padding_data2[511:0] : extra_padding_data1[511:0];

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        dout[511:0] <= 512'b0;
    else if(extra_padding_d)
        dout[511:0] <= extra_padding_data[511:0];
    else if(padding_tag)
        dout[511:0] <= padding_data[511:0];
    else if(msg_vld)
        dout[511:0] <= msg_dat[511:0];
end

endmodule
